package com.yifeng.repo.micro.service.server.auth.sso.filter.context;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yifeng.repo.base.utils.converter.JacksonHelper;
import com.yifeng.repo.micro.service.server.auth.sso.filter.context.SsoAuthInfo;
import com.yifeng.repo.micro.service.server.auth.sso.filter.util.Base62;
import com.yifeng.repo.micro.service.server.engine.core.JsonRequestWrapper;
import org.apache.commons.io.IOUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Openx请求头解析器
 * @author zyh
 * create on 2023/4/12 9:50
 */
public class OpenxHeaderParser {
    private static final String OPENX_HEADER_KEY = "_openx_header";
    private static final Pattern SSO_AUTH_PATTERN = Pattern.compile(OPENX_HEADER_KEY + "=.*?&" + "|" + OPENX_HEADER_KEY + "=.*?$");
    private static final String OPENX_HEAD_KEY = "_openx_head";

    public static SsoAuthInfo parser(HttpServletRequest request)  {
        try {
            JsonNode jsonNode = resolveHeader(request);
            if(jsonNode != null && !jsonNode.isEmpty()) {
                SsoAuthInfo ssoAuthInfo = JacksonHelper.toObj(jsonNode.toString(), SsoAuthInfo.class);
                JsonNode tokenJsonNode = jsonNode.get("token");
                if(tokenJsonNode != null) {
                    ssoAuthInfo.setUserToken(tokenJsonNode.get("userToken").textValue());
                }
                return ssoAuthInfo;
            }
            return null;
        } catch (IOException e) {
            throw new RuntimeException("openx header parse failed, error={}", e);
        }
    }

    private static JsonNode resolveHeader(HttpServletRequest httpServletRequest) throws IOException {
        // first parse from get http://xxx.xxx.xx?_openx_header=xxx&t=xxx
        HttpServletRequest request = new JsonRequestWrapper(httpServletRequest);
        String headerFromQuery = request.getQueryString();
        if(StringUtils.hasText(headerFromQuery)) {
            Matcher matcher = SSO_AUTH_PATTERN.matcher(headerFromQuery);
            if(matcher.find()) {
                String group = matcher.group().replaceFirst(OPENX_HEADER_KEY + "=", "");
                String decode = group.endsWith("&")? Base62.decode(group.substring(0, group.length() - 1)) : Base62.decode(group);
                return new ObjectMapper().readTree(decode);
            }
        }

        // second parse from multipart/form-data -> _openx_header={xxxx}
        String headerFromForm = request.getParameter(OPENX_HEADER_KEY);
        if(StringUtils.hasText(headerFromForm)) {
            return new ObjectMapper().readTree(Base62.decode(headerFromForm));
        }

        // third parse from application/json -> {_openx_head:"xxx"}
        ServletInputStream inputStream = request.getInputStream();
        if(inputStream != null) {
            String body = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
            if(StringUtils.hasText(body)) {
                JsonNode headerFromBody = new ObjectMapper().readTree(body);
                return headerFromBody.at("/" + OPENX_HEAD_KEY);
            }
            return null;
        }
        return null;
    }

    public static void main(String[] args) {
        String head = "_openx_header=Uo9jPN9ZQ65kT28wUo9XR6bXSo8w8kURYkIuiEMafx2YDhx2Q8lo8i8cDlP6KYEY9vPcHvPY8i8cDlRdHXOtH9P4vrRM9bSY8w8ZGpCZKoCZ4vE3WnC30qCJWvDY8i8cDlRdHXOtHGPN9pRsvDRs9fR6KYEY8nDJamC30mC30mCI8i8cDlRdHXOtHGPN9pRsvEOMrb8ZeYwBQ5vwwX8YmYQMGYEY8rOpGvOZ9YDp9XP6CvCJ0mC34rPZ0oOs4YB29fRMSYEbjTB29fRdHoRo8w8kQvbkMDbx2URYkIuiEMafx2YDhx2Q8lo8i8cvXRMKYEYBdcuhakB3bfAVeZQx3cYBzYVImYT6x1hPMuYEdiYOMHaScLpSo8w8Z4mBZ0kE30kCJ4m8YmYP6LsQMDb8ZeYEJ8sPMKrPcKjCpDZEIqqPJGvBJavOZWjCsOoOcGvCZ1cOp0u8YmYSsLpSsblRY8w8Z0vCJOpHaOsHZ8mHJ51H3OtCaOtDqOnE391HJWtH4Ks8YmYTNDbSaDlP6KYEY8sCJOsCs4mCZ5bDJanD30mC35cD30pD6OYB29rSsLoJc5jPI8w8kUKiEMzWEQMXo8i8dLpPN9KRsjbRY8w8ZKqCc4oD3WrBJ0oD6CjD6DXDorXDZSuBJbYE3TZEMGoD3KuPY9x1B29rSsLo8Zfy8cDoPM5qPLHfRMKYEZ4sCpGmE3aqCpSmC30i8cba8ZeYDZ4sDZDXC38nPJKvCJGmC30nPZGmCpHc8YmYR6x1dQMuYEcPXR7DbB29jPN9ZQ65kT4ba8ZeYDMCqEM8oOZSoOMHZEJ4mC30nDMOmCcDX8YmYRMx1YQMnb8ZeYCJWvCp8qCp0nDp0YB29kTMrYPN8YEY8mC38oCZ4oD28i8cx1oPqba8ZeYC6LcPZbYPZWjD3bXDoqnCMLYBJbaEJGjC6CqCc4nE3KtDJCu8YmYS65oPMvqIMGYEY8mPJbcOJ0vDIqqEM4tBJ4nPM8jEMGvD2qmOpGoOJ4uDJSrCpWYB29mRtDq8ZeYIc5sOUMtfUUeYx2MuY28i8d1lStH3RsHb8ZeYCJ0mC30sC3GYB29pT65qTNCYEY8n8YmYTNDbSavXRMKYEYBdbB3bl83cbeSYVND&t=1661852171783";
        Matcher matcher = SSO_AUTH_PATTERN.matcher(head);
        if (matcher.find()) {
            System.out.println("openxHeader is" + matcher.group());
        }
    }

}
